import React from 'react'
import ReactDOM from 'react-dom'
import $ from 'jquery'
import _ from 'underscore'
import classnames from 'classnames';

export class Draggable {
  constructor(target, container = target) {
    this.target = target;
    this.container = container;

    this.start = this.start.bind(this);
    this.move = this.move.bind(this);
    this.end = this.end.bind(this);

    this.target.onmousedown = this.start;
  }

  start(e) {
    this.lastMouseX = e.pageX;
    this.lastMouseY = e.pageY;

    document.onmousemove = this.move;
    document.onmouseup = this.end;
  }

  move(e) {
    let $container = $(this.container)
      , x = e.pageX - this.lastMouseX + parseInt($container.css('left'))
      , y = e.pageY - this.lastMouseY + parseInt($container.css('top'));

    $container.css({
      left: x + 'px',
      top: y + 'px'
    });

    this.lastMouseX = e.pageX;
    this.lastMouseY = e.pageY;
  }

  end(e) {
    document.onmousemove = null;
    document.onMouseup = null;
  }

  dispose() {
    this.target.onmousedown = null;
    this.target = null;
    this.container = null;
  }
}

export default class Modal extends React.Component {
  constructor(props, context) {
    super(props, context);

    this.position = props.defaultPosition;

    if (this.props.Scope) {
      this.scope = new this.props.Scope(props);
      this.scope.viewInstance = this;
      this.state = this.scope.state();
    }

    this.close = this.close.bind(this);
  }

  static mount(props = {}, parent = document.body) {
    let container = document.createElement('div');
    $(container).css({
      position: 'absolute',
      left: '0px',
      top: '0px',
      width: '100%',
      height: '100%',
      zIndex: 1000
    }).appendTo(parent);

    let parameters = _.defaults({}, props, this.defaultProps || {}, Modal.defaultProps);
    return ReactDOM.render(<this {...parameters} />, container, function () {
      this.__container = container;
    });
  }

  static unMount(dialog) {
    let container = dialog.__container;
    ReactDOM.unmountComponentAtNode(container);
    $(container).remove();
  }

  /**
   * 关闭当前对话框。
   * @param  {any} args 支持传入任何值，该值可以在父级组件的 onClose 回调中得到：
   *   1. 一般用于判断是否需要刷新列表。
   *   2. 当没有参数传递时，可能会有系统缺省的事件参数 e 传入。
   * @return {undefined}      当前函数没有任何返回值。
   */
  close(args) {
    Modal.unMount(this);
    this.props.onClose(args);
  }

  resizeModal() {
    let $dialog = $(this.refs.dialog)
      , $body = $(this.refs.body)
      , $child = $body.children()
      , bodyHeight = $body.height()
      , paddingTop = parseInt($body.css('padding-top'))
      , paddingBottom = parseInt($body.css('padding-bottom'))
      , childHeight = $child.height()
      , marginTop = parseInt($child.css('margin-top'))
      , marginBottom = parseInt($child.css('margin-bottom'))
      , realHeight = childHeight + marginTop + marginBottom

    if (this.props.fixed) {
      if ($dialog.height() > window.innerHeight) {
        $body.css({
          height: (window.innerHeight - this.props.fixedHeight),
          overflowY: 'scroll',
          overflowX: 'hidden'
        });
      }

      if ((bodyHeight - paddingTop - paddingBottom) > childHeight) {
        $body.css({
          height: '',
          overflowY: '',
          overflowX: ''
        });
      }

      $(document.body).css({
        overflowY: 'hidden'
      })
    }

    if (!this.props.defaultPosition) {
      $dialog.css({
        marginLeft: (window.innerWidth - $dialog.width()) / 2,
        marginTop: (window.innerHeight - $dialog.height()) / 2
      });
    }
  }

  componentDidMount() {
    this.resizeModal();

    if (this.props.draggable) {
      this.__draggable = new Draggable(this.refs.header, this.refs.dialog);
    }

    if(this.scope){
      this.scope.bind(this);
    }
  }

  componentDidUpdate() {
    this.resizeModal();
  }

  componentWillUnmount() {
    if (this.props.draggable) {
      this.__draggable.dispose();
    }

    $(document.body).css({
      overflowY: ''
    });

    if(this.scope){
      this.scope.unbind(this);
    }
  }

  renderHeader() {
    return (
      <h4>需要重写renderHeader方法</h4>
    );
  }

  renderBody() {
    return (
      <div>需要重写renderBody方法</div>
    );
  }

  renderFooter() {
    return (
      <div>需要重写renderFooter方法</div>
    );
  }

  render() {
    let styleObj = {
      left: '0px',
      top: '0px',
      position: 'absolute'
    };

    if (this.position) {
      styleObj.left = this.position.x;
      styleObj.top = this.position.y;
    }

    let clickEvent = this.props.closeable ? {onClick: this.close} : null;

    return (
      <div style={{ position: 'fixed'}}>
        <div style={{ position: 'relative' }} className={ classnames(this.props.className) }>
          <div ref="dialog" className="dialog" style={ styleObj }>
            <div className="dialog-header" ref="header">
              <a className="close iconfont" href="javascript:;" onClick={ this.close }>&#xe63d;</a>
              { this.renderHeader() }
            </div>
            <div ref="body" className="dialog-content">
              { this.renderBody() }
            </div>
            <div className="dialog-footer">
              { this.renderFooter() }
            </div>
          </div>
          {
            this.props.modal
              ? (
                <div className="dialog-backdrop" onClick={ this.close }></div>
              ) : null
          }
        </div>
      </div>
    )
  }
}

Modal.defaultProps = {
  modal: true,
  draggable: true,
  fixed: true,
  fixedHeight: 220,
  defaultPosition: null,
  onClose: () => {},
  Scope: null,
  className: ''
}
